using namespace std;

#include "Archivo.h"

Archivo::Archivo(std::string nombreArchivo,
		EstrategiaAlmacenamiento* eAlmacenamiento, int longBloque) {
	this->estrategiaAlm = eAlmacenamiento;
	this->nombreArchivo = nombreArchivo;
	this->existeMetadata = false;
	this->longBloque = longBloque;
	this->cantidadBloques = 0;

	this->estrategiaAlm->abrir(this);
}

//Metodos de Interfaz

int Archivo::escribir(Componente& componente, int offset) {
	if (this->metadata->getTipo() == 'r') {
		Registro* registro = dynamic_cast<Registro*> (&componente);
		return this->escribirRegistro(*registro, offset);
	} else if (this->metadata->getTipo() == 'b') {
		Bloque* bloque = dynamic_cast<Bloque*> (&componente);
		return this->escribirBloque(*bloque, offset);
	}
	return 1;
}

Componente* Archivo::leer(int offset) {
	if (this->metadata->getTipo() == 'r') {
		Registro* reg = new Registro(this->leerRegistro(offset));
		return reg;
	} else if (this->metadata->getTipo() == 'b') {
		Bloque* bloque = new Bloque(this->leerBloqueCompleto(offset));
		return bloque;
	}
	return NULL;
}

void Archivo::borrarComp(int offset) {
	if (this->metadata->getTipo() == 'r') {
		this->borrarRegistro(offset);
	}
}

void Archivo::imprimir() {
	if (this->metadata->getTipo() == 'r') {
		this->imprimirRegistro();
	} else if (this->metadata->getTipo() == 'b') {
		this->imprimirBloque();
	}else if (this->metadata->getTipo() == 't'){
		this->imprimirTexto();
	}
}

//Metodos
int Archivo::getLongBloque() {
	return this->longBloque;
}

int Archivo::getcantidadBloques() {
	return this->cantidadBloques;
}

int Archivo::aumentarComponentesBloques() {
	this->cantidadBloques++;
	return this->cantidadBloques;
}

string& Archivo::getNombreArch() {
	return this->nombreArchivo;
}

void Archivo::setNombreArchivo(string s) {
	this->nombreArchivo = s;
}

fstream* Archivo::getFileAux() {
	return &this->fileaux;
}

int Archivo::buscarEspacioLibre(int tamanio) {
	// Devuelve la posicion del bloque (0 es el primero) o -1 si no hay lugar.
	// NO borra o descuenta nada.

	int libre = 0;
	unsigned int contador = 0;
	do {
		if (this->offsetsEspLibre.size() == contador)
			return -1;
		libre = this->offsetsEspLibre[contador];
		if (tamanio == 0) {
			return libre;
		}

		contador++;
	} while (libre < tamanio);
	return contador - 1;
}

Metadata* Archivo::abrir(char t) {
	switch (t) {
	case 'b':
		this->file.open(nombreArchivo.c_str(), ios::out | ios::in | ios::binary);
		if (!file.is_open())
			file.open(nombreArchivo.c_str(), ios::out | ios::in | ios::binary
					| ios::trunc);
		if (!file.eof()) {
			Metadata* meta = new Metadata('0', 0); //Cualquier input;
			file >> ((*meta));
			comienzoDeDatos = file.tellg();
			if (meta->getTipo() == 'r')
				longBloque = meta->getTamanio();
			this->abrirArchEspacios();
			return meta;
		} else
			return NULL;
		break;
	case 't':
		this->file.open(nombreArchivo.c_str(), ios::out | ios::in);
		if (!file.is_open())
			file.open(nombreArchivo.c_str(), ios::out | ios::in | ios::trunc);
		if (!file.eof()) {
			string auxString("");
			char auxTipo;
			int auxTamanio;
			int auxcantidadDatos;
			getline(file, auxString);
			auxTipo = auxString.c_str()[0];//tipo
			auxString.clear();
			getline(file, auxString);
			auxTamanio = atoi(auxString.c_str());//tama�o
			auxString.clear();
			getline(file, auxString);
			auxcantidadDatos = atoi(auxString.c_str());//tama�o
			auxString.clear();
			list<string> auxList;
			list<bool> auxListb;
			getline(file, auxString);//tipodato
			while (!file.eof() && auxString != "FIN METADATA") {
				auxList.push_back(auxString);
				auxString.clear();
				getline(file, auxString);//clave o no
				if (auxString.c_str()[0] == '1') {
					auxListb.push_back(true);
				} else
					auxListb.push_back(false);
				auxString.clear();
				getline(file, auxString);//tipodato
			}
			comienzoDeDatos = file.tellg();
			Metadata* meta = new Metadata(auxTipo, auxTamanio,
					auxcantidadDatos, auxList, auxListb);
			this->setMetadata(meta);
			this->abrirArchEspacios();
			return meta;
		} else
			return NULL;
		break;
	default:
		this->file.open(nombreArchivo.c_str(), ios::out | ios::in | ios::binary);
		cout << "ERROR DE PARAMETRO AL ARBRIR ARCHIVO" << endl;
		return NULL;
	}
	return NULL;
}

void Archivo::cerrar() {
	this->file.close();
	this->fileaux.close();
}

void Archivo::crearMetadata(char tipo, int tamanio, list<string> tipos, list<
		bool> claves) {
	delete this->metadata;
	this->metadata = new Metadata(tipo, tamanio, tipos.size(), tipos, claves);
	this->file << (*(metadata));
	this->comienzoDeDatos = file.tellp();
	if (tipo == 'r')
		this->longBloque = tamanio;
	cout << "Metadata creada exitosamente." << endl;
}
void Archivo::inicializarMetadata(char tipo) {
	this->metadata = new Metadata(tipo, 0);
}
//devuelve pos final del archivo..
int Archivo::eof() {
	file.seekg(0, ios::end);
	return file.tellg();
}

int Archivo::getOffsetComienzoDatos() {
	return this->comienzoDeDatos;
}

//Binario

void* Archivo::leer(int& offset, string tipo) {
	int tamanio;

	if (tipo == "int") {
		int* valor = NULL;
		tamanio = sizeof(int);
		this->file.read((char*) valor, tamanio);
		offset += tamanio;
		return valor;
	} else if (tipo == "char") {
		char* valor = NULL;
		tamanio = sizeof(char);
		this->file.read((char*) valor, tamanio);
		offset += tamanio;
		return valor;
	} else if (tipo == "double") {
		double* valor = NULL;
		tamanio = sizeof(double);
		this->file.read((char*) valor, tamanio);
		offset += tamanio;
		return valor;
	}
	return 0;
}

int Archivo::escribir(int offset, string tipo, void* valor) {
	int tamanio;

	if (tipo == "int") {
		int* valorAux = (int*) valor;
		tamanio = sizeof(int);
		this->file.write((char*) valorAux, tamanio);
		return offset + tamanio;
	} else if (tipo == "char") {
		char* valorAux = (char*) valor;
		tamanio = sizeof(char);
		this->file.write((char*) valorAux, tamanio);
		return offset + tamanio;
	} else if (tipo == "double") {
		double* valorAux = (double*) valor;
		tamanio = sizeof(double);
		this->file.write((char*) valorAux, tamanio);
		return offset + tamanio;
	}
	return 0;
}

//TEXTO

void Archivo::imprimirTexto() {
	if (!this->getExisteMetadata()) {
		cout << "NO EXISTE METADATA: IMPOSIBLE IMPRIMIR TEXTO" << endl;
		return;
	}
	cout << "Imprimiendo Texto:" << endl;
	for (int i = 0; i < this->getcantidadBloques(); i++) {
		Registro* reg = dynamic_cast<Registro*> (this->leerTexto(i));
		cout << "Registro[" << i << "]:" << endl;
		cout << (*reg) << endl;
	}

}

//este metodo esta de mas?
//devuelve el offset del registro para borrar o sobreescribir que coincide con el comienzo de linea
int Archivo::buscarRegistro(Registro registro) {
	string strgAux;
	bool encontrado = false;
	bool buscando = true;
	file.seekg(0, ios::end);
	int fin = file.tellg();
	file.seekg(this->comienzoDeDatos, ios::beg);
	int posInicialReg = 0;
	list<string>::iterator it;
	list<void*>::iterator it2;
	while (!encontrado && file.tellg() != fin) {
		buscando = true;
		it = registro.getTipos().begin();
		it2 = registro.getValores().begin();
		posInicialReg = file.tellg();
		while (it != registro.getTipos().end()) {
			getline(file, strgAux);//datoo
			if (buscando) {
				if ((*it) == "int") {
					int auxInt = atoi(strgAux.c_str());
					if (auxInt != *((int*) (*it2)))
						buscando = false;
				} else if ((*it) == "char") {
					char auxChar = strgAux.c_str()[0];
					if (auxChar != *((char*) (*it2)))
						buscando = false;
				} else if ((*it) == "double") {
					double auxDouble = atof(strgAux.c_str());
					if (auxDouble != *((double*) (*it2)))
						buscando = false;
				}
			}
			it++;
			it2++;
		}
		if (buscando)
			encontrado = true;
	}
	if (encontrado)
		return posInicialReg;
	else
		return 0;
}

void Archivo::modificarTexto(Componente& componente) {
	if (!existeMetadata) {
		cout << "NO EXISTE METADATA: IMPOSIBLE MODIFICAR" << endl;
		return;
	}
	Registro* registro = dynamic_cast<Registro*> (&componente);
	int offset = this->buscarRegistro(*registro);
	if (offset == 0) {
		cout << "NO EXISTE REGISTRO: IMPOSIBLE MODIFICAR" << endl;
	} else {
		fstream auxfile;
		auxfile.open("auxiliar.txt", fstream::in | fstream::out | fstream::app
				| fstream::trunc);
		file.seekg(0, ios::beg);
		string strgAux;
		while (file.tellg() != offset) {
			getline(file, strgAux);
			auxfile << strgAux << endl;
		}
		list<void*>::iterator it = registro->getValores().begin();
		while (it != registro->getValores().end()) {
			auxfile << (*it) << endl; //Si punteros a void agregar un * para obetener dato
		}
		while (!file.eof()) {
			getline(file, strgAux);
			auxfile << strgAux << endl;
		}
		auxfile.seekg(0, ios::beg);
		file.close();
		file.open(nombreArchivo.c_str(), fstream::in | fstream::out
				| fstream::app | fstream::trunc);
		file << auxfile;
		file.close();
		file.open(nombreArchivo.c_str(), fstream::in | fstream::out);
		auxfile.close();
	}
}

void Archivo::borrarTexto(Componente& componente) {
	if (!existeMetadata) {
		cout << "NO EXISTE METADATA: IMPOSIBLE BORRAR" << endl;
		return;
	}
	Registro* registro = dynamic_cast<Registro*> (&componente);
	int offset = this->buscarRegistro(*registro);
	if (offset == 0) {
		cout << "NO EXISTE REGISTRO: IMPOSIBLE MODIFICAR" << endl;
	} else {
		fstream auxfile("auxiliar.txt");
		auxfile.open("auxiliar.txt", fstream::in | fstream::out | fstream::app);
		file.seekg(0, ios::beg);
		string strgAux;
		while (file.tellg() != offset) {
			getline(file, strgAux);
			auxfile << strgAux << endl;
		}
		for (unsigned int i = 0; i < (registro->getTipos().size() * 2); i++) {
			getline(file, strgAux);
		}
		while (!file.eof()) {
			getline(file, strgAux);
			auxfile << strgAux << endl;
		}
		auxfile.seekg(0, ios::beg);
		file.close();
		file.open(nombreArchivo.c_str(), fstream::in | fstream::out
				| fstream::app | fstream::trunc);
		file << auxfile;
		file.close();
		file.open(nombreArchivo.c_str(), fstream::in | fstream::out);
		auxfile.close();
		this->cantidadBloques--;
	}
}

void Archivo::escribirTexto(Componente& componente) {

	Registro* registro = dynamic_cast<Registro*> (&componente);

	list<void*>::iterator it = registro->getValores().begin();
	list<bool>::iterator it1 = registro->getClaves().begin();
	list<string>::iterator it2 = registro->getTipos().begin();

	if (!existeMetadata) {
		int auxInt;
		file << 't' << endl; //TIPO
		auxInt = sizeof(*registro);
		file << auxInt << endl; //TAMA�O REG
		auxInt = registro->getTipos().size();
		file << auxInt << endl; //CANTIDAD DATOS
		while (it2 != registro->getTipos().end()) {
			file << (*it2) << endl;//tipo
			file << (*it1) << endl;//clave
			it++;
			it2++;
		}
		file << "FIN METADATA" << endl;
		Metadata* meta = new Metadata('t', sizeof(*registro),
				registro->getTipos().size(), registro->getTipos(),
				registro->getClaves());
		this->setMetadata(meta);
	}
	this->file.seekp(0, ios::end);
	it2 = registro->getTipos().begin();
	while (it != registro->getValores().end()) {
		//CONTROLAR ESTOS CASTEOS 0 FE
		if ((*it2) == "int") {
			file << *((int*) (*it)) << endl;
		} else if ((*it2) == "char") {
			file << *((char*) (*it)) << endl;
		} else if ((*it2) == "double") {
			file << *((double*) (*it)) << endl;
		} else
			cout << "ERROR DE TIPO EN ARCHIVO ESCRIBIR" << endl;
		it2++;
		it++;
	}
	this->cantidadBloques++;
}

Componente* Archivo::leerTexto(int numeroReg) {
	if (!existeMetadata) {
		cout << "NO EXISTE METADATA: IMPOSIBLE LEER" << endl;
		throw 1;
	}
	RegistroFijo* reg = new RegistroFijo();
	string aux("");
	file.seekg(0, ios::end);
	unsigned int i;
	//Pasa de largo metadata
	for (i = 0; i < ((2 * metadata->getTipoDatos().size()) + 4); i++) {
		getline(file, aux);
		aux.clear();
	}
	//queda en el comienzo de datos
	unsigned int j;
	for (i = 1; (int) i < numeroReg; i++) {
		for (j = 0; i < metadata->getTipoDatos().size(); j++) {
			getline(file, aux);
			aux.clear();
		}
	}
	//queda para leer
	list<string>::iterator it = this->metadata->getTipoDatos().begin();
	list<bool>::iterator it2 = this->metadata->getTipoDatosClaves().begin();
	getline(file, aux);
	while (!file.eof()) {
		if ((*it) == "int") {
			int valor = atoi(aux.c_str());
			reg->addCampo(valor, (*it2));
		}
		if ((*it) == "char") {
			char valor = aux.c_str()[0];
			reg->addCampo(valor, (*it2));
		}
		if ((*it) == "double") {
			double valor = atof(aux.c_str());
			reg->addCampo(valor, (*it2));
		}
		aux.clear();
		getline(file, aux);
		it++;
		it2++;
	}
	return reg;
}

//ARCHIVO ESPACIO EN BLANCO

void Archivo::abrirArchEspacios() {
	string aux = nombreArchivo.substr(0, nombreArchivo.length() - 4);//.dat afuera
	aux += "aux.dat";
	this->fileaux.open(aux.c_str(), fstream::in | fstream::out
			| fstream::binary);
	if (!this->fileaux.is_open())
		this->fileaux.open(aux.c_str(), fstream::in | fstream::out
				| fstream::trunc | fstream::binary);
	else {
		int valor;
		file.seekg(0, ios::beg);
		while (!fileaux.eof()) {
			fileaux.read((char*) &valor, sizeof(valor));
			this->offsetsEspLibre.push_back(valor);//queda invertida
		}
		//invierto
		int size = offsetsEspLibre.size();
		int temp;
		for (int i = 0; i < size / 2; i++) {
			temp = offsetsEspLibre[size - 1 - i];
			offsetsEspLibre[size - 1 - i] = offsetsEspLibre[i];
			offsetsEspLibre[i] = temp;
		}
	}
	//si no existe lo crea, si existe lo abre ylevanta list espacios libres...
}

void Archivo::borrarArchEspacios(int offset) {//SOLO REGISTROS
	string nombreaux = this->nombreArchivo.substr(0, nombreArchivo.size() - 4);
	nombreaux += "aux.dat";
	this->fileaux.close();
	this->fileaux.open(nombreaux.c_str(), fstream::in | fstream::out
			| fstream::trunc | fstream::binary);
	this->fileaux.seekp(0, ios::beg);
	for (unsigned int i = 0; i < offsetsEspLibre.size(); i++) {
		if (offsetsEspLibre[i] != offset)
			this->fileaux.write((char*) &offsetsEspLibre[i], sizeof(int));
		else
			offsetsEspLibre.erase(offsetsEspLibre.begin() + i);
	}
}

void Archivo::agregarArchEspacio(int offset_tamanio) {
	this->offsetsEspLibre.push_back(offset_tamanio);
	fileaux.seekp(0, ios::end);
	fileaux.write((char*) &offset_tamanio, sizeof(offset_tamanio));
}

void Archivo::modificarArchEspacio(int nbloque, int tamanioreg) {//SOLO BLOQUES
	int tamanio;
	this->fileaux.seekg(0, ios::beg);
	for (int i = 0; i < nbloque; i++) {
		this->fileaux.read((char*) &tamanio, sizeof(tamanio));
	}
	tamanio = tamanio - tamanioreg;
	this->offsetsEspLibre[nbloque] = tamanio;
	this->fileaux.seekp(fileaux.tellg(), ios::beg);
	this->fileaux.write((char*) &tamanio, sizeof(tamanio));

}

//MANEJO DE BLOQUES

int Archivo::escribirBloque(Bloque& componente, int nbloque) {
	int cantRegistros = componente.getCantidadComponentes();

	if (!this->getExisteMetadata()) {
		int tamanio = this->getLongBloque();
		if(cantRegistros > 0){
			Registro r = componente.getComponente(0);
			list<bool> claves = r.getClaves();
			list<string> tipos = r.getTipos();
			this->crearMetadata('b', tamanio, tipos, claves);
		} else {
			throw 1;
		}
	}

	int offset = this->getOffsetComienzoDatos() + nbloque * this->getLongBloque();

	//escribo cantidad de registros en el bloque
	int offsetAux = this->escribir(offset, "int", (void*) &cantRegistros);

	//por cada registro en el bloque...
	for(int i=0; i < cantRegistros; i++){
		Registro r = componente.getComponente(i);
		//escribo tamanio del registro en archivo
		int tamanioRegistro = r.getTamanio();
		offsetAux = this->escribir(offsetAux, "int", (void*) &tamanioRegistro);

		list<void*>::iterator itVal = r.getValores().begin();
		list<string>::iterator itTip = r.getTipos().begin();
		list<int>::iterator itCant = r.getCantidades().begin();

		while (itVal != r.getValores().end()) {
			offsetAux = this->escribir(offsetAux, "int", &(*itCant));
			for (int i = 0; i < *itCant; i++) {
				offsetAux = this->escribir(offsetAux, *itTip, *itVal);
				itVal++;
			}
			itTip++;
			itCant++;
		}
	}

	int tamanioBloqueRestante = this->getLongBloque() - componente.getEspacioOcupado();

	//espacio en blanco del bloque...
	/*if (nuevo)
		this->agregarArchEspacio(tamanioBloqueRestante);
	else*/
	// el modificar deberia agregar si el offset esta mas alla del eof
	this->modificarArchEspacio(nbloque, tamanioBloqueRestante);

	char cero = 0;
	for (int i = 0; i < tamanioBloqueRestante; i++) {
		offsetAux = this->escribir(offsetAux, "char", (void*) &cero);
	}
	return offset;
}

void Archivo::imprimirBloque() {
	if (!this->getExisteMetadata()) {
		cout << "NO EXISTE METADATA: IMPOSIBLE IMPRIMIR BLOQUES" << endl;
		return;
	}
	this->getMetadata()->imprimir();
	int cantidadBloques = this->getcantidadBloques();
	cout << "Imprimiendo bloques: " << endl << endl;
	for (int i = 0; i < cantidadBloques; i++) {
		cout << "\tBloque[" << i << "]:" << endl;
		Bloque bloque = this->leerBloqueCompleto(i);
		cout << bloque << endl;
	}

}

/*void Archivo::almacenarBloqueModificacion(int nbloque, Bloque& bloque) {

	int offsetAux = this->getOffsetComienzoDatos() + nbloque
			* this->getLongBloque();

	//escribo cantidad de componentes en archivo
	int cantidadComponentesBloques = bloque.getCantidadComponentes();
	offsetAux = this->escribir(offsetAux, "int",
			(void*) &cantidadComponentesBloques);

	int tamanioBloqueRestante = this->getLongBloque();

	for (int j = 0; j < cantidadComponentesBloques; j++) {
		//escribo tamanio del componente en archivo
		int tamanioComponente = bloque.getComponente(j).getTamanio();

		offsetAux
				= this->escribir(offsetAux, "int", (void*) &tamanioComponente);

		//escribo datos
		list<void*>::iterator itVal =
				bloque.getComponente(j).getValores().begin();
		list<string>::iterator itTip =
				bloque.getComponente(j).getTipos().begin();
		list<int>::iterator itCant =
				bloque.getComponente(j).getCantidades().begin();

		while (itVal != bloque.getComponente(j).getValores().end()) {
			offsetAux = this->escribir(offsetAux, "int", &(*itCant));
			for (int i = 0; i < *itCant; i++) {
				offsetAux = this->escribir(offsetAux, *itTip, *itVal);
				itVal++;
			}
			itTip++;
			itCant++;
		}
		//asumimos que el registro es menor en tamanio que el bloque
		tamanioBloqueRestante -= tamanioComponente;

	}

	this->modificarArchEspacio(nbloque, tamanioBloqueRestante);

	char cero = 0;
	for (int i = 0; i < tamanioBloqueRestante; i++) {
		offsetAux = this->escribir(offsetAux, "char", (void*) &cero);
	}
}*/

Bloque Archivo::leerBloqueCompleto(int nbloque) {
	Bloque bloque(this->getLongBloque());
	int offset = this->getOffsetComienzoDatos() + nbloque
			* this->getLongBloque();

	//leo cant componentes
	int* cantComponentes;
	int offsetAux = offset;
	cantComponentes = (int*) this->leer(offsetAux, "int");

	int* cantidadElementos;

	list<string>::iterator itTipo;
	list<bool>::iterator itClave;

	//Por cada componente
	for (int i = 0; i < *cantComponentes; i++) {

		RegistroVariable reg;

		itTipo = this->getMetadata()->getTipoDatos().begin();
		itClave = this->getMetadata()->getTipoDatosClaves().begin();

		//Por cada tipo de dato
		while (itTipo != this->getMetadata()->getTipoDatos().end()) {

			//Leo cantidad de elementos del mismo tipo
			cantidadElementos = (int*) this->leer(offsetAux, "int");

			if (*itTipo == "int") {
				int* miLista = new int[*cantidadElementos];
				for (int j = 0; j < *cantidadElementos; j++) {
					int* temp = (int*) this->leer(offsetAux, *itTipo);
					miLista[j] = *temp;
				}
				reg.addCampo((void*) &miLista, *itClave, *itTipo,
						*cantidadElementos);
				delete miLista;
			} else if (*itTipo == "char") {
				char* miLista = new char[*cantidadElementos];
				for (int j = 0; j < *cantidadElementos; j++) {
					char* temp = (char*) this->leer(offsetAux, *itTipo);
					miLista[j] = *temp;
				}
				reg.addCampo((void*) &miLista, *itClave, *itTipo,
						*cantidadElementos);
				delete miLista;
			} else if (*itTipo == "double") {
				double* miLista = new double[*cantidadElementos];
				for (int j = 0; j < *cantidadElementos; j++) {
					double* temp = (double*) this->leer(offsetAux, *itTipo);
					miLista[j] = *temp;
				}
				reg.addCampo((void*) &miLista, *itClave, *itTipo,
						*cantidadElementos);
				delete miLista;
			} else {
				void** miLista = new void*[*cantidadElementos];
				for (int j = 0; j < *cantidadElementos; j++) {
					void* temp = (void*) this->leer(offsetAux, *itTipo);
					miLista[j] = temp;
				}
				reg.addCampo(miLista, *itClave, *itTipo, *cantidadElementos);
				delete miLista;
			}

			itTipo++;
			itClave++;
		}
		bloque.addComponente(reg);
	}
	return bloque;
}

//MANEJO DE REGISTROS FIJOS

int Archivo::escribirRegistro(Registro componente, int offset) {

	list<void*> valores = componente.getValores();
	list<string> tipos = componente.getTipos();

	if (!this->getExisteMetadata()) {
		int tamanio = componente.getTamanio();
		list<bool> claves = componente.getClaves();
		this->crearMetadata('r', tamanio, tipos, claves);
	}

	list<void*>::iterator itValores = valores.begin();
	list<string>::iterator itTipos = tipos.begin();
	while (itValores != valores.end()) {
		offset = this->escribir(offset, *itTipos, *itValores);
		itValores++;
		itTipos++;
	}
	this->borrarArchEspacios(offset);

	return offset;
}

Registro Archivo::leerRegistro(int offset) {

	if (!this->getExisteMetadata()) {
		cout << "No existe la metadata. No se puede recuperar el registro."
				<< endl;
		throw 1;
	}

	RegistroFijo* nuevoRegistro = new RegistroFijo();

	list<string>::iterator itTipos =
			this->getMetadata()->getTipoDatos().begin();
	list<bool>::iterator itClaves =
			this->getMetadata()->getTipoDatosClaves().begin();
	while (itTipos != this->getMetadata()->getTipoDatos().end()) {
		bool clave = *itClaves;
		void* valor = this->leer(offset, *itTipos);
		nuevoRegistro->addCampo(valor, clave, *itTipos);
		itTipos++;
	}

	return (*nuevoRegistro);
}

void Archivo::borrarRegistro(int offset) {
	this->agregarArchEspacio(offset);
}

void Archivo::imprimirRegistro() {
	if (!this->getExisteMetadata()) {
		cout << "NO EXISTE METADATA: IMPOSIBLE IMPRIMIR REGISTROS" << endl;
		return;
	}
	this->getMetadata()->imprimir();
	int offset = this->getOffsetComienzoDatos();
	int contador = 0;
	cout << "Imprimiento registros:" << endl;
	while (offset != this->eof()) {
		Registro* registro = new Registro(this->leerRegistro(offset));
		//RegistroFijo* reg = static_cast<RegistroFijo*> (&());
		cout << "\tRegistro[" << contador << "]:" << endl;
		cout << (*registro) << endl;
		contador++;
		offset += registro->getTamanio();
	}
}
